package com.xxl.sso.core.login;

import com.alibaba.fastjson.JSONObject;
import com.xxl.sso.core.conf.Conf;
import com.xxl.sso.core.exception.XxlSsoException;
import com.xxl.sso.core.filter.XxlSsoProperties;
import com.xxl.sso.core.store.SpringContextUtils;
import com.xxl.sso.core.store.SsoLoginStore;
import com.xxl.sso.core.store.SsoSessionIdHelper;
import com.xxl.sso.core.user.XxlSsoUser;
import com.xxl.sso.core.util.CookieUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

/**
 * @author xuxueli 2018-04-03
 */
@Slf4j
public class SsoWebLoginHelper {

    /**
     * client login
     *
     * @param response
     * @param sessionId
     * @param ifRemember    true: cookie not expire, false: expire when browser close （server cookie）
     * @param xxlUser
     */
    public static void login(HttpServletRequest request,HttpServletResponse response,
                             String sessionId,
                             XxlSsoUser xxlUser,
                             boolean ifRemember) {
        String storeKey = SsoSessionIdHelper.parseStoreKey(sessionId);
        if (storeKey == null) {
            throw new RuntimeException("parseStoreKey Fail, sessionId:" + sessionId);
        }
        // 仅允许单个客户端登录，移除其他登录用户
        XxlSsoProperties xxlSsoProperties = SpringContextUtils.getBean(XxlSsoProperties.class);
        if(!ObjectUtils.isEmpty(xxlSsoProperties)
                && !ObjectUtils.isEmpty(xxlSsoProperties.getSingleClientEnable())
                && xxlSsoProperties.getSingleClientEnable()){
            String userId = SsoSessionIdHelper.parseUserId(sessionId);
            if(!ObjectUtils.isEmpty(userId)){
                // 批量删除已登录用户
                SsoLoginStore.removeByPrefix(userId.concat("_"));
            }
        }
        SsoLoginStore.put(storeKey, xxlUser);
        log.info("########################SsoWebLoginHelper login sessionId:{}",sessionId);
        CookieUtil.set(request,response, Conf.SSO_SESSIONID, sessionId, ifRemember);
    }

    /**
     * client logout
     *
     * @param request
     * @param response
     */
    public static void logout(HttpServletRequest request,
                              HttpServletResponse response) {
        String cookieSessionId = CookieUtil.getValue(request, Conf.SSO_SESSIONID);
        log.info("##########################SsoWebLoginHelper logout cookieSessionId:{}",cookieSessionId);
        if (cookieSessionId==null) {
            return;
        }

        String storeKey = SsoSessionIdHelper.parseStoreKey(cookieSessionId);
        log.info("##########################SsoWebLoginHelper logout storeKey:{}",storeKey);
        if (storeKey != null) {
            SsoLoginStore.remove(storeKey);
        }

        CookieUtil.remove(request, response, Conf.SSO_SESSIONID);
    }



    /**
     * login check
     *
     * @param request
     * @param response
     * @return
     */
    public static XxlSsoUser loginCheck(HttpServletRequest request, HttpServletResponse response){
        String cookieSessionId = CookieUtil.getValue(request, Conf.SSO_SESSIONID);
        log.info("####################1.SsoWebLoginHelper loginCheck, path:{},cookieSessionId:{}",request.getPathInfo(),cookieSessionId);
        // cookie user
        XxlSsoUser xxlUser = SsoTokenLoginHelper.loginCheck(cookieSessionId);
        if (xxlUser != null) {
            return xxlUser;
        }

        // redirect user

        // remove old cookie
        log.info("####################2.SsoWebLoginHelper loginCheck removeSessionIdByCookie.");
        SsoWebLoginHelper.removeSessionIdByCookie(request, response);

        // set new cookie
        String paramSessionId = request.getParameter(Conf.SSO_SESSIONID);
        log.info("####################3.SsoWebLoginHelper loginCheck paramSessionId:{}",paramSessionId);
        xxlUser = SsoTokenLoginHelper.loginCheck(paramSessionId);
        if (xxlUser != null) {
            log.info("####################4.SsoWebLoginHelper loginCheck xxlUser:{}", JSONObject.toJSONString(xxlUser));
            CookieUtil.set(request,response, Conf.SSO_SESSIONID, paramSessionId, false);    // expire when browser close （client cookie）
            return xxlUser;
        }
        log.info("####################4.SsoWebLoginHelper loginCheck xxlUser is null");
        return null;
    }


    /**
     * client logout, cookie only
     *
     * @param request
     * @param response
     */
    public static void removeSessionIdByCookie(HttpServletRequest request, HttpServletResponse response) {
        CookieUtil.remove(request, response, Conf.SSO_SESSIONID);
    }

    /**
     * get sessionid by cookie
     *
     * @param request
     * @return
     */
    public static String getSessionIdByCookie(HttpServletRequest request) {
        String cookieSessionId = CookieUtil.getValue(request, Conf.SSO_SESSIONID);
        return cookieSessionId;
    }

    private static String buildCaptchaCacheKey(String key){
        return Conf.SSO_CAPTCHACODE.concat("#").concat(key);
    }

    /**
     * 缓存验证码
     * @param response
     * @param captchaCode
     */
    public static void cacheCaptcha(HttpServletRequest request,HttpServletResponse response, String captchaCode) {
        String uuid = UUID.randomUUID().toString();
        SsoLoginStore.put(buildCaptchaCacheKey(uuid),captchaCode);
        log.info("########################SsoWebLoginHelper cacheCaptcha uuid:{},captchaCode:{}",uuid,captchaCode);
        CookieUtil.set(request,response, Conf.SSO_CAPTCHACODE, uuid, false);
    }

    /**
     * 校验验证码
     * @param request
     * @param captchaCode
     */
    public static void captchaCodeCheck(HttpServletRequest request, HttpServletResponse response, String captchaCode) {
        if(ObjectUtils.isEmpty(captchaCode)){
            throw new XxlSsoException("验证码为空，请重新输入!");
        }
        String storeKey = CookieUtil.getValue(request, Conf.SSO_CAPTCHACODE);
        if(ObjectUtils.isEmpty(storeKey)){
            throw new XxlSsoException("验证码已过期，请刷新后重试!");
        }
        String storeValue = SsoLoginStore.getStoreValue(buildCaptchaCacheKey(storeKey));
        if(!captchaCode.equalsIgnoreCase(storeValue)){
            throw new XxlSsoException("验证码校验失败!");
        }
        // 校验成功移除缓存和cookie
        SsoLoginStore.remove(storeKey);
        CookieUtil.remove(request, response, Conf.SSO_CAPTCHACODE);
    }
}
